import time
import serial.tools.list_ports
import serial
import threading
import tkinter as tk
from tkinter import scrolledtext
from tkinter import filedialog

class SerialMonitorApp:
    def __init__(self, root):
        self.root = root
        self.root.title("PT_HAO_SSCOM_V001")
        
        self.serial_port = None             # 端口选择
        self.serial_thread = None
        self.port_status = tk.StringVar()  # 串口状态变量
        self.port_status.set("串口未打开")
        
        self.create_widgets()
        
    def create_widgets(self):
        # Serial Port Selection Frame
        self.port_frame = tk.Frame(self.root)
        self.port_frame.pack(pady=5)

        tk.Label(self.port_frame, text="端口").pack(side=tk.LEFT)
        self.port_var = tk.StringVar()
        self.port_menu = tk.OptionMenu(self.port_frame, self.port_var, "")
        self.port_menu.pack(side=tk.LEFT)
        self.update_serial_ports()

        self.baud_frame = tk.Frame(self.root)
        self.baud_frame.pack(pady=5)

        tk.Label(self.baud_frame, text="波特率").pack(side=tk.LEFT)
        self.baud_var = tk.IntVar()
        self.baud_var.set(9600)  # 默认的波特率
        baud_values = [9600, 19200, 38400, 57600, 115200]  # Common baud rates
        self.baud_menu = tk.OptionMenu(self.baud_frame, self.baud_var, *baud_values)
        self.baud_menu.pack(side=tk.LEFT)

        self.export_button = tk.Button(self.baud_frame, text="导出数据", command=self.export_data)
        self.export_button.pack(side=tk.LEFT, padx=10)

        self.open_close_button = tk.Button(self.port_frame, text="打开串口", command=self.toggle_port)
        self.open_close_button.pack(side=tk.LEFT, padx=10)
        
        self.update_uart = tk.Button(self.port_frame, text="更新串口", command=self.update_serial_ports)
        self.update_uart.pack(side=tk.LEFT, padx=0)
        
        # Text Display Frame
        self.text_frame = tk.Frame(self.root)
        self.text_frame.pack(padx=10, pady=5, fill=tk.BOTH, expand=True)
        
        self.text_area = scrolledtext.ScrolledText(self.text_frame, wrap=tk.WORD)
        self.text_area.pack(fill=tk.BOTH, expand=True)
        
        # Input Frame
        self.input_frame = tk.Frame(self.root)
        self.input_frame.pack(pady=5)
        
        self.input_label = tk.Label(self.input_frame, text="输入:")
        self.input_label.pack(side=tk.LEFT)
        
        self.input_entry = tk.Entry(self.input_frame, width=50)
        self.input_entry.pack(side=tk.LEFT)
        self.input_entry.bind("<Return>", self.send_data)
        
        self.send_button = tk.Button(self.input_frame, text="发送", command=self.send_data)
        self.send_button.pack(side=tk.LEFT, padx=10)
        
        # Status Bar
        self.status_var = tk.StringVar()
        self.status_label = tk.Label(self.root, textvariable=self.status_var, bd=1, relief=tk.SUNKEN, anchor=tk.W)
        self.status_label.pack(side=tk.BOTTOM, fill=tk.X)

        # Port Status Label
        self.port_status_label = tk.Label(self.root, textvariable=self.port_status, bd=1, relief=tk.SUNKEN, anchor=tk.W)
        self.port_status_label.pack(side=tk.BOTTOM, fill=tk.X)

        self.clear_button = tk.Button(self.input_frame, text="清除", command=self.clear_text)
        self.clear_button.pack(side=tk.LEFT, padx=10)

    # 清除窗口数据
    def clear_text(self):
        self.text_area.delete(1.0, tk.END)

    # 更新端口的列表
    def update_serial_ports(self):
        ports = serial.tools.list_ports.comports()
        port_names = [port.device for port in ports]
        self.port_menu["menu"].delete(0, "end")
        for port in ports:
            port_label = f"{port.description}"
            self.port_menu["menu"].add_command(label=port_label, command=lambda value=port.device: self.port_var.set(value))
        if port_names:
            self.port_var.set(port_names[0])

    def toggle_port(self):
        if self.serial_port and self.serial_port.isOpen():
            self.close_port()
        else:
            self.open_port()

    # 串口的开 并且显示端口的状态更新
    def open_port(self):
        port = self.port_var.get()
        baud_rate = self.baud_var.get()
        try:
            self.serial_port = serial.Serial(port, baud_rate, timeout=0.5)
            self.status_var.set(f"打开端口{port}成功.")
            self.port_status.set("串口已打开")  # 更新串口状态
            self.open_close_button.config(text="关闭串口")
            self.start_serial_thread()
        except serial.SerialException:
            self.status_var.set(f"打开端口失败:{port}.")

    # 串口的关闭 并且显示端口的状态更新
    def close_port(self):
        if self.serial_port and self.serial_port.isOpen():
            self.serial_port.close()
            self.status_var.set("串口已关闭.")
            self.port_status.set("串口未打开")  # 更新串口状态
            self.open_close_button.config(text="打开串口")

    # 串口的线程
    def start_serial_thread(self):
        if self.serial_thread is None or not self.serial_thread.is_alive():
            self.serial_thread = threading.Thread(target=self.serial_monitor)
            self.serial_thread.daemon = True
            self.serial_thread.start()

    # 接收数据
    def serial_monitor(self):
        while True:
            if self.serial_port and self.serial_port.isOpen():
                data = self.serial_port.readline().decode("utf-8")
                if data:
                    self.text_area.insert(tk.END, f"{self.get_timestamp()}收→⭐:{data}")
                    self.text_area.see(tk.END)
            time.sleep(0.1)

    # 发送数据
    def send_data(self, event=None):
        if self.serial_port and self.serial_port.isOpen():
            send_data = self.input_entry.get()
            self.serial_port.write(send_data.encode("utf-8") + b"\r\n")
            self.text_area.insert(tk.END, f"{self.get_timestamp()}发→⭐:{send_data}\n")
            self.text_area.see(tk.END)
            self.input_entry.delete(0, tk.END)

    # 时间戳显示
    def get_timestamp(self):
        return time.strftime("[%H:%M:%S] ")

    # 用于导出数据
    def export_data(self):
        file_path = tk.filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files", "*.txt")])
        if file_path:
            with open(file_path, "w", encoding="utf-8") as file:
                file.write(self.text_area.get("1.0", tk.END))


def main():
    root = tk.Tk()
    app = SerialMonitorApp(root)
    root.mainloop()

if __name__ == "__main__":
    main()
